package cn.echo.ecc.service.impl;

import cn.echo.ecc.domain.KillActivity;
import cn.echo.ecc.domain.KillCourse;
import cn.echo.ecc.enums.GlobalExceptionCode;
import cn.echo.ecc.exception.GlobalCustomException;
import cn.echo.ecc.mapper.KillActivityMapper;
import cn.echo.ecc.service.IKillActivityService;
import cn.echo.ecc.service.IKillCourseService;
import cn.echo.ecc.util.AssertUtil;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author hulan
 * @since 2022-10-20
 */
@Service
public class KillActivityServiceImpl extends ServiceImpl<KillActivityMapper, KillActivity> implements IKillActivityService {

    @Autowired
    private IKillCourseService killCourseService;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private RedissonClient redissonClient;
    /**
     * 发布活动
     * @param id
     */
    @Override
    @Transactional
    public void publish(Long id) {
        // 1.使用JSR303进行参数校验
        // 2.校验秒杀活动是否存在，活动状态是否未发布
        KillActivity killActivity = selectById(id);
        AssertUtil.isNotNull(killActivity,GlobalExceptionCode.KILL_ACTIVITY_IS_NULL_ERROR);
        boolean activityState = KillActivity.WAIT_STATE == killActivity.getPublishStatus();
        AssertUtil.isTrue(activityState,GlobalExceptionCode.KILL_ACTIVITY_STATE_ERROR);
        // 3.校验当前发布时间是否在活动开始时间之前
        Date now = new Date();
        boolean before = now.before(killActivity.getStartTime());
        AssertUtil.isTrue(before,GlobalExceptionCode.KILL_ACTIVITY_STATE_ERROR);
        // 4.校验秒杀活动中是否有秒杀课程
        List<KillCourse> killCourses = killCourseService.selectKillCourseByActivityId(id);
        if (killCourses== null || killCourses.size() < 0) {
            throw new GlobalCustomException(GlobalExceptionCode.KILL_COURSE_IS_NULL_ERROR);
        }
        // 5.将数据存入redis，设置信号量，修改发布时间和状态
        killCourses.forEach(killCourse -> {
            String key = id + ":" + killCourse.getId();
            RSemaphore semaphore = redissonClient.getSemaphore(key);
            boolean permits = semaphore.trySetPermits(killCourse.getKillCount());
            if (permits) {
                redisTemplate.opsForHash().put(
                        "activity:" + id,
                        killCourse.getId().toString(),
                        killCourse
                );
                killCourse.setPublishStatus(KillCourse.ON_STATE);
                killCourse.setPublishTime(now);
                killCourseService.updateById(killCourse);
            }
        });
        // 6.修改秒杀活动的状态和时间
        killActivity.setPublishStatus(KillActivity.ON_STATE);
        killActivity.setPublishTime(now);
        updateById(killActivity);
    }

    /**
     * 取消发布
     * @param id
     */
    @Override
    @Transactional
    public void cancelPublish(Long id) {
        // 1.使用JSR303进行参数校验
        // 2.校验秒杀活动是否存在，活动状态是否发布中
        KillActivity killActivity = selectById(id);
        AssertUtil.isNotNull(killActivity,GlobalExceptionCode.KILL_ACTIVITY_IS_NULL_ERROR);
        boolean activityState = KillActivity.ON_STATE == killActivity.getPublishStatus();
        AssertUtil.isTrue(activityState,GlobalExceptionCode.KILL_IS_CANCEL_ERROR);
        // 3.从redis中删除
        redisTemplate.delete("activity:" + id);
        // 4.修改秒杀课程状态
        List<KillCourse> killCourses = killCourseService.selectKillCourseByActivityId(id);
        killCourses.forEach(killCourse -> {
            redisTemplate.delete(id + ":" + killCourse.getId());

            killCourse.setPublishStatus(KillCourse.CANCEL_STATE);
            killCourseService.updateById(killCourse);
        });
        killActivity.setPublishStatus(KillActivity.CANCEL_STATE);
        updateById(killActivity);
    }
}
